package mine.auction;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;

/**
 * A simple model of an mine.auction. The mine.auction maintains a list of items of
 * arbitrary length.
 * 
 * This class shouldn't be used in a multi-thread context as the lists used in
 * this implementation are not thread-safe.
 */
public class Auction implements IAuction {

	// The list of items in this mine.auction.
	private ArrayList<Item> items;

	// The map of users and the items on which they have a bid.
	// Multimap from google collect gives a way to associate keys
	// with arbitrarily many values. In the HashMultimap implementation
	// the values behave like a HashSet, i.e. no duplicates.
	private Multimap<User, Item> itemsPerUser = HashMultimap.create();

	// The number that will be given to the next item entered
	// into this mine.auction.
	private int nextItemNumber;

	/**
	 * Create a new mine.auction.
	 */
	public Auction() {
		items = new ArrayList<Item>();
		nextItemNumber = 1;
	}

	@Override
	public int addItem(String description) {
		items.add(new Item(nextItemNumber, description));
		return nextItemNumber++;
	}

	@Override
	public boolean recordBid(int itemNumber, User bidder, long value) {
		Item selectedItem = getItem(itemNumber);
		if (selectedItem != null) {
			if (selectedItem.bidFor(new Bid(bidder, value))) {
				itemsPerUser.put(bidder, selectedItem);
				System.out.println("The bid for item number " + itemNumber
						+ " was successful.");
				return true;
			} else {
				System.out.println("item number: " + itemNumber
						+ " already has a bid of: "
						+ selectedItem.getHighestBid().getValue());
				return false;
			}
		} else {
			System.out
					.println("item number: " + itemNumber + " doesn't exist ");
			return false;
		}
	}

	@Override
	public Bid getHighestBid(int number) {
		return getItem(number) != null ? getItem(number).getHighestBid() : null;
	}

	@Override
	public List<Bid> getBids(int number) {
		return getItem(number) != null ? getItem(number).getBids() : null;
	}

	@Override
	public Collection<Item> getItemsBidBy(User user) {
		return itemsPerUser.get(user);
	}

	@Override
	public void printItems() {
		Iterator<Item> it = items.iterator();
		while (it.hasNext()) {
			Item item = (Item) it.next();
			System.out.println(item.getNumber() + ": " + item.getDescription());
			// Include any details of a highest bid.
			Bid highestBid = item.getHighestBid();
			if (highestBid != null) {
				System.out.println("    Bid: " + highestBid.getValue());
			} else {
				System.out.println("    (No bid)");
			}
		}
	}

	@Override
	public void printItems(User user) {
		Iterator<Item> it = getItems(user);
		while (it != null && it.hasNext()) {
			Item item = (Item) it.next();
			System.out.println(item.getNumber() + ": " + item.getDescription());
		}
	}

	@Override
	public Item getItem(int number) {
		if ((number >= 1) && (number < nextItemNumber)) {
			// The number seems to be reasonable.
			Item selectedItem = (Item) items.get(number - 1);
			// Include a confidence check to be sure we have the
			// right item.
			if (selectedItem.getNumber() != number) {
				System.err.println("Error: " + "Wrong item returned. "
						+ "Number: " + number);
			}
			return selectedItem;
		} else {
			System.out.println("item number: " + number + " does not exist.");
			return null;
		}
	}

	private Iterator<Item> getItems(User user) {
		Collection<Item> items = itemsPerUser.get(user);
		if (items != null) {
			return itemsPerUser.get(user).iterator();
		} else {
			return null;
		}
	}
}
